package org.vaadin.nf4v.core.handler.impl;

import org.vaadin.nf4v.core.NavigableApplication;
import org.vaadin.nf4v.core.config.ContextConfigurationException;
import org.vaadin.nf4v.core.handler.HomePageResolver;
import org.vaadin.nf4v.core.handler.UriHandler;
import org.vaadin.nf4v.core.navigation.InvalidUriException;
import org.vaadin.nf4v.core.navigation.NavigationManager;
import org.vaadin.nf4v.core.navigation.target.NavigationTarget;

/**
 * Default implementation of UriHandler.
 * The only configuration available is separator character between uri and parameters part.
 * By default it's "/" character.
 */
public class DefaultUriHandler implements UriHandler {
    
    // separator between uri and parameters string
    private String separator;

    public DefaultUriHandler(String separator) {
        if (separator == null || "".equals(separator.trim())) {
            throw new ContextConfigurationException("Separator symbol can't be empty");
        }
        this.separator = separator;
    }

    @Override
    public NavigationTarget parseUri(String fragment) throws InvalidUriException {

        String context = NavigationManager.getNavigationContext();
        // should be impossible, but to be sure
        if (context == null) {
            throw new IllegalStateException("Can't detect current context");
        }

        NavigationTarget target = new NavigationTarget();
        if (fragment == null || fragment.trim().equals("")) {
            target.setHomePage(true);
            target.setPageClass(NavigableApplication.getCurrent().getNavigationConfig()
                    .getHandler(HomePageResolver.class, context).resolveHomePage(context));
            target.setUri(NavigableApplication.getCurrent().getNavigationConfig().getPageConfig(context, target.getPageClass()).getUri());
            target.setRequireUriChange(true); // may be request to context root, but home page has it's own uri, so we need to append it
        } else {
            String[] fragmentParts = fragment.split(separator, 2);
            target.setUri(fragmentParts[0]);

            if (fragmentParts.length > 1) {
                String params = fragmentParts[1];
                if (params != null && !"".equals(params.trim())) {
                    target.setParamsString(params);
                }
            }

            target.setPageClass(NavigableApplication.getCurrent().getNavigationConfig().getPageClass(context, target.getUri()));
            if (target.getPageClass() == null) {
                if (!fragment.startsWith(separator)) { // todo think: parameter may be represented differently, so it's hard to detect correctly here
                    // page doesn't exist in config
                    // navigator should catch this exception and provide correct user feedback
                    throw new InvalidUriException("Uri '" + fragment + "' is invalid for context '" + context + "'", true, false);
                } else {
                    // It starts with "/" and means there is no page name on purpose because it's the home page.
                    // i.e. http://mycompany.com/#/param1/param2     In that case param1 is no page name but a parameter of the home page.
                    // => we display no error message

                    // What we believed to be the page name is probably part of the parameters for the home page.
                    if (!fragment.equals(separator)) {
                        target.setParamsString(fragment.substring(separator.length()));
                    }
                }
                target.setHomePage(true);
                target.setPageClass(NavigableApplication.getCurrent().getNavigationConfig()
                        .getHandler(HomePageResolver.class, context).resolveHomePage(context));
                target.setUri(NavigableApplication.getCurrent().getNavigationConfig().getPageConfig(context, target.getPageClass()).getUri());
                target.setRequireUriChange(true); // may be request to context root, but home page has it's own uri, so we need to append it
            }
        }

        return target;
    }

    @Override
    public String composeUri(NavigationTarget target) {
        String uri = target.getUri();
        String params = target.getParamsString();
        if (params == null || params.trim().equals("")) {
            return uri;
        }
        return uri + separator + params;
    }
}
